package cn.ant.config;

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * RabbitMQ一些配置信息，交换机、队列等创建和绑定
 *
 * @author Anhui AntLaddie <a href="https://juejin.cn/user/4092805620185316">(掘金蚂蚁小哥)</a>
 * @version 1.0
 **/
@Configuration
public class RabbitMQConfig {

    // 直接交换机名称
    public static final String EXCHANGE_NAME = "MsgHandleExchange";
    // 队列名称
    public static final String QUEUE_NAME = "MsgHandleQueue";
    // 路由key
    public static final String ROUTING_KEY = "MsgHandleKey";
    // 声明死信交换机名称
    public static final String DLX_EXCHANGE = "DLXExchange";
    // 声明死信队列名称
    public static final String DLX_QUEUE = "DLXQueue";
    // 声明路由绑定关系 Routing Key 死信交换机到死信队列
    public static final String DLX_KEY = "DLXKey";

    //+++++++++++++++++配置了直连交换机和队列的关系

    /***
     * 一个普通的直连交换机
     * @return Exchange
     */
    @Bean("msgHandleExchange")
    public Exchange msgHandleExchange() {
        // 第一种方式：使用new的方式，是什么类型交换机我们就创建什么xxxExchange
        //  参数1：exchange: 交换机名称
        //  参数2：durable: 是否需要持久化
        //  参数3：autoDelete: 当最后一个绑定到Exchange上的队列删除后，自动删除该Exchange
        //  参数4：arguments: 扩展参数，用于扩展AMQP协议定制化使用
        // Exchange directExchange = new DirectExchange(EXCHANGE_NAME,true,false,null);
        // 当前Exchange是否用于RabbitMQ内部使用，默认为False
        // 使用默认即可directExchange.isInternal();

        //第二种方式：使用Builder方式
        return ExchangeBuilder
                .directExchange(EXCHANGE_NAME)    // 交换机名称
                .durable(true)           // 是否需要持久化
                .autoDelete()                     // 交换机自动删除
                //.withArguments(null)              // 扩展参数
                .build();
    }

    /***
     * 一个普通的队列
     * @return Queue
     */
    @Bean("msgHandleQueue")
    public Queue msgHandleQueue() {
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~设置死信参数Start
        // 绑定死信队列（参数设置）
        Map<String, Object> arguments = new HashMap<>();
        // 正常队列设置死信交换机 参数key是固定值；（就是说死去的消息发送到哪个交换机）
        arguments.put("x-dead-letter-exchange", DLX_EXCHANGE);
        // 正常队列设置死信交换机到死信队列绑定Routing Key
        // 参数key是固定值（就是说死去的消息在交换机里通过什么路由发送到死信队列）
        arguments.put("x-dead-letter-routing-key", DLX_KEY);
        // 设置正常队列的长度限制 为3
        // arguments.put("x-max-length",3);
        // 队列设置消息过期时间 60 秒
        // arguments.put("x-message-ttl", 60 * 1000);
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~设置死信参数End

        // 第一种方式：使用new的方式；这种和原生创建一样
        //   参数一：队列名称
        //   参数二：队列里的消息是否持久化，默认消息保存在内存中，默认false
        //   参数三：该队列是否只供一个消费者进行消费的独占队列，
        //           为true（仅限于此连接），false（默认，可以多个消费者消费）
        //   参数四：是否自动删除，最后一个消费者断开连接以后，该队列是否自动删除true自动删除，默认false
        //   参数五：构建队列的其它属性，看下面扩展参数
        // Queue queue = new Queue(QUEUE_NAME,true,false,false,arguments);
        // 原生： channel.queueDeclare(QUEUE_NAME, true, false, false, arguments);

        // 第二种方式：使用Builder方式
        return QueueBuilder.durable(QUEUE_NAME).withArguments(arguments).build();
    }

    /***
     * 队列绑定到交换机
     * @param msgHandleExchange 交换机名称
     * @param msgHandleQueue 队列名称
     * @return Binding
     */
    @Bean("queueBindDirectExchange")
    public Binding queueBindDirectExchange(
            @Qualifier("msgHandleExchange") Exchange msgHandleExchange,
            @Qualifier("msgHandleQueue") Queue msgHandleQueue) {
        return BindingBuilder
                .bind(msgHandleQueue).to(msgHandleExchange).with(ROUTING_KEY).noargs();
    }

    // +++++++++++++++++配置死信交换机的一系列信息

    /***
     * 死信交换机
     * @return Exchange
     */
    @Bean("DLXExchange")
    public Exchange dLXExchange() {
        return ExchangeBuilder.directExchange(DLX_EXCHANGE).durable(true).build();
    }

    /***
     * 死信队列
     * @return Queue
     */
    @Bean("DLXQueue")
    public Queue dLXQueue() {
        return QueueBuilder.durable(DLX_QUEUE).build();
    }

    /***
     * 死信交换机上面绑定死信队列
     * @return Binding
     */
    @Bean("dlxQueueBindDlxExchange")
    public Binding dlxQueueBindDlxExchange(@Qualifier("DLXExchange") Exchange dLXExchange,
                                           @Qualifier("DLXQueue") Queue dLXQueue) {
        // 死信交换机上面绑定死信队列
        return BindingBuilder.bind(dLXQueue).to(dLXExchange).with(DLX_KEY).noargs();
    }
}
